package com.lintf.batch.controller;

import com.lintf.batch.api.ThirdPartyStudentApi;
import com.lintf.batch.domain.Student;
import com.lintf.batch.service.StudentService;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

/**
 * @ author lintf
 * @ system Mac
 * @ data 2025/8/15
 * @ package_name com.lintf.batch.controller
 * @ project_name my-diy-project
 * @ desc
 */
@Slf4j
@RestController
@RequiredArgsConstructor
public class BatchController {

    private final StudentService studentService;
    private final JobLauncher jobLauncher;
    private final PlatformTransactionManager transactionManager;
    private final Job syncStudentsJob;
    private final ExecutorService manualExecutor;

    private final int PAGE_SIZE = 1000;
    private final int TOTAL_PAGES = 100; // 200条 / 每页10条 = 20页

    /**
     * 应用启动后的初始化方法
     * 输出应用相关信息和使用说明
     */
    @PostConstruct
    public void init() {
        System.out.println("== 学生数据同步Demo已启动 ==");
        System.out.println("总记录数: " + ThirdPartyStudentApi.TOTAL_RECORDS);
        System.out.println("每页大小: " + PAGE_SIZE);
        System.out.println("总页数: " + TOTAL_PAGES);
        System.out.println("访问 /batch 测试Spring Batch方案");
        System.out.println("访问 /manual 测试手动分页多线程方案");
        System.out.println("访问 /reset 重置计数器");
    }

    /**
     * 触发Spring Batch方案执行学生数据同步
     *
     * @return 执行结果信息
     * @throws Exception 执行过程中可能抛出的异常
     */
    @GetMapping("/batch")
    public String runBatch() throws Exception {
        studentService.resetCounters();
        // 创建唯一的作业参数
        long startTime = System.currentTimeMillis();
        JobParameters jobParameters = new JobParametersBuilder()
                .addLong("timestamp", System.currentTimeMillis())
                .toJobParameters();
        JobExecution execution = jobLauncher.run(syncStudentsJob, jobParameters);

        long duration = System.currentTimeMillis() - startTime;
        return String.format(
                "Spring Batch执行完成! \n" +
                        "耗时: %d ms \n" +
                        "处理记录数: %d \n" +
                        "错误数: %d \n" +
                        "状态: %s",
                duration,
                studentService.getProcessedCount(),
                studentService.getErrorCount(),
                execution.getExitStatus().getExitCode()
        );
    }

    /**
     * 触发手动分页多线程方案执行学生数据同步
     *
     * @return 执行结果信息
     */
    @GetMapping("/manual")
    public String runManual() {
        studentService.resetCounters();
        long startTime = System.currentTimeMillis();

        manualStudentSync();

        long duration = System.currentTimeMillis() - startTime;
        return String.format(
                "手动分页多线程执行完成! \n" +
                        "耗时: %d ms \n" +
                        "处理记录数: %d \n" +
                        "错误数: %d",
                duration,
                studentService.getProcessedCount(),
                studentService.getErrorCount()
        );
    }

    /**
     * 重置计数器
     *
     * @return 重置成功提示信息
     */
    @GetMapping("/reset")
    public String reset() {
        studentService.resetCounters();
        return "计数器已重置";
    }

    /**
     * 执行手动分页多线程同步操作
     * 将所有页面分配给线程池中的线程进行并行处理
     */
    public void manualStudentSync() {
        studentService.resetCounters();
        int page = 0;
        List<Future<?>> futures = new ArrayList<>();

        // 处理所有页面（0到19页）
        while (page < TOTAL_PAGES) {
            final int currentPage = page++;
            Future<?> future = manualExecutor.submit(() -> {
                // 为每页创建独立事务
                TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());

                try {
                    List<Student> students = ThirdPartyStudentApi.fetchStudentsByManual(currentPage, PAGE_SIZE);
                    if (!students.isEmpty()) {
                        studentService.saveStudents(students);
                    }
                    transactionManager.commit(status);
                } catch (Exception e) {
                    transactionManager.rollback(status);
                    studentService.recordError("处理第" + currentPage + "页数据时出错", e);
                }
            });
            futures.add(future);
        }

        // 等待所有任务完成
        for (Future<?> future : futures) {
            try {
                future.get();
            } catch (InterruptedException | ExecutionException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

}

